# encoding: utf-8
"""
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    created by siyi.chen on '16/01/2025'
    comment: mqtt客户端
"""
import asyncio
import random
from config import Config
import paho.mqtt.client as mqtt
from project.lib.common import logger_mqtt


class AsyncMQTT:

    def __init__(self, client_id=None):
        self.broker = Config.MQTT.get('broker')
        self.port = Config.MQTT.get('port')
        # 如果未提供客户端 ID，则生成一个随机的 ID
        self.client_id = client_id or f'mqtt_client_{random.randint(0, 65535)}'
        self.client = mqtt.Client(client_id=self.client_id)
        # 绑定回调函数
        self.client.on_connect = self.on_connect
        self.client.on_disconnect = self.on_disconnect
        self.client.on_message = self.on_message

    async def connect(self):
        """ 异步连接到 MQTT 代理并启动事件循环
        """
        self.client.connect(self.broker, self.port)  # 不要使用connect_async，会导致on_message无法触发，connect底层调用的就是connect_async
        self.client.loop_start()

    async def disconnect(self):
        """ 断开与 MQTT 代理的连接并停止事件循环
        """
        self.client.loop_stop()
        self.client.disconnect()

    async def subscribe(self, topic, qos):
        """ 订阅指定的MQTT主题
        :param topic: 要订阅的主题名称
        :param qos: 消息的服务质量等级 (0:最多一次，1:至少一次，2:仅一次)
        """
        self.client.subscribe(topic, qos)

    async def publish(self, topic, message, qos):
        """
        发布消息到指定的MQTT主题
        :param topic: 要发布消息的主题
        :param message: 要发布的消息内容
        :param qos: 消息的服务质量等级 (0:最多一次，1:至少一次，2:仅一次)
        """
        # 构造完整的主题，以项目名称区分环境
        full_topic = f"{Config.PROJECT_NAME}/{topic}"
        result = self.client.publish(full_topic, message, qos=qos)
        status = result[0]
        if status == mqtt.MQTT_ERR_SUCCESS:
            logger_mqtt.info(f"{self.client_id} 发布消息 {message} 到主题 {full_topic}")
        else:
            logger_mqtt.error(f"{self.client_id} 向主题 {full_topic} 发布消息失败，错误码: {status}")

    # 连接回调函数
    def on_connect(self, client, userdata, flags, rc):
        if rc == 0:
            logger_mqtt.info(f"已连接到 MQTT 代理 {self.client_id}")
        else:
            logger_mqtt.error(f"连接失败，返回码 {rc}")

    # 断开连接回调函数
    def on_disconnect(self, client, userdata, rc):
        if rc != 0:
            logger_mqtt.error(f"{self.client_id} 意外断开连接，返回码 {rc}")
        logger_mqtt.info(f"{self.client_id} 断开连接")

    # 当接收到订阅主题的消息时调用的回调函数
    def on_message(self, client, userdata, msg):
        logger_mqtt.info(f"{self.client_id} 收到主题 {msg.topic} 的消息：{msg.payload.decode()}")

async def main():
    topic = "test/topic"
    message = "Hello, MQTT!"

    async_mqtt = AsyncMQTT()
    await async_mqtt.connect()
    await async_mqtt.subscribe(topic, qos=2)

    for i in range(5):
        await async_mqtt.publish(topic, f"{message} - {i}")
        await asyncio.sleep(1)  # 模拟异步发送间隔

    await asyncio.sleep(5)  # 等待消息接收完成
    await async_mqtt.disconnect()

if __name__ == '__main__':
    print("=======启动服务=======")
    asyncio.run(main())
